package com.dao.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.dao.QuestionDAO;
import com.model.Question;
import com.model.Tag;
import com.util.Page;

@Repository
public class QuestionDAOImpl implements QuestionDAO {

	@Autowired
	private SessionFactory sessionFactory;

	public Question findById(int id) {
		Question q = (Question) sessionFactory.getCurrentSession().get(Question.class, id);
		return q;
	}

	public void add(Question question) {
		sessionFactory.getCurrentSession().save(question);
	}

	public void update(Question question) {
		sessionFactory.getCurrentSession().update(question);
	}

	public boolean delete(int id) {
		Question question = (Question) sessionFactory.getCurrentSession().get(Question.class, id);
		if (null == question) {
			return false;
		}
		if (question.getIsAnswered() == 1) {
			return false;
		}
		else {
			sessionFactory.getCurrentSession().delete(question);
			return true;
		}
	}

	private void changeIgnore(int id, int ignoreType) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "update Question as q set q.isIgnore=:isIgnore where q.id=:id";
		Query q = s.createQuery(hql);
		q.setInteger("isIgnore", ignoreType);
		q.setInteger("id", id);
		q.executeUpdate();
	}

	public void ignore(int id) {
		this.changeIgnore(id, 1);
	}

	public void unIgnore(int id) {
		this.changeIgnore(id, 0);
	}

	public void agree(int id) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "update Question as q set q.agreeNum=q.agreeNum+1 where q.id=:id";
		Query q = s.createQuery(hql);
		q.setInteger("id", id);
		q.executeUpdate();
	}

	public void disagree(int id) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "update Question as q set q.disagreeNum=q.disagreeNum+1 where q.id=:id";
		Query q = s.createQuery(hql);
		q.setInteger("id", id);
		q.executeUpdate();
	}

	public void favor(int id) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "update Question as q set q.favorNum=q.favorNum+1 where q.id=:id";
		Query q = s.createQuery(hql);
		q.setInteger("id", id);
		q.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	public Page findByPage(int userId, int page, int pageSize, String condition, boolean isPublic) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "select q.*,u.id as user_id,u.name as user_name,u.head_img as user_head,ub.id as user_by_id,ub.name as user_by_name,ub.head_img as user_by_head"
				+ " from question q inner join user u on q.user_id=u.id inner join user ub on q.question_user_id=ub.id where q.user_id=:userId";
		String hqlC = "select count(*) from question q where q.user_id=:userId";
		if ("answered".equals(condition)) {
			hql = hql + " and q.is_answered = :isAnswered";
			hqlC = hqlC + " and q.is_answered = :isAnswered";
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.answer_at desc";
		}
		if ("unanswered".equals(condition)) {
			hql = hql + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			hqlC = hqlC + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.question_at desc";
		}
		if ("ignore".equals(condition)) {
			hql = hql + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			hqlC = hqlC + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.question_at desc";
		}

		Query query = s.createSQLQuery(hql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		Query queryc = s.createSQLQuery(hqlC);

		query.setInteger("userId", userId);
		queryc.setInteger("userId", userId);

		if ("answered".equals(condition)) {
			query.setInteger("isAnswered", 1);
			queryc.setInteger("isAnswered", 1);
		}
		if ("unanswered".equals(condition)) {
			query.setInteger("isAnswered", 0);
			query.setInteger("ignore", 0);
			queryc.setInteger("isAnswered", 0);
			queryc.setInteger("ignore", 0);
		}
		if ("ignore".equals(condition)) {
			query.setInteger("isAnswered", 0);
			query.setInteger("ignore", 1);
			queryc.setInteger("isAnswered", 0);
			queryc.setInteger("ignore", 1);
		}

		query.setMaxResults(pageSize);
		query.setFirstResult((page - 1) * pageSize);

		int count = Integer.parseInt((queryc.uniqueResult().toString()));
		Page pageIns = new Page(count, pageSize, page);
		pageIns.setList(query.list());
		return pageIns;
	}

	public Page findSendQuestionsByPage(int userId, int page, int pageSize, String condition,
			boolean isPublic) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "select q.*,u.id as user_id,u.name as user_name,u.head_img as user_head,ub.id as user_by_id,ub.name as user_by_name,ub.head_img as user_by_head"
				+ " from question q inner join user u on q.user_id=u.id inner join user ub on q.question_user_id=ub.id where q.question_user_id=:userId";
		String hqlC = "select count(*) from question q where q.user_id=:userId";

		if ("all".equals(condition)) {
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.question_at desc";
		}

		if ("answered".equals(condition)) {
			hql = hql + " and q.is_answered = :isAnswered";
			hqlC = hqlC + " and q.is_answered = :isAnswered";
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.question_at desc";
		}
		if ("unanswered".equals(condition)) {
			hql = hql + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			hqlC = hqlC + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.question_at desc";
		}
		if ("ignore".equals(condition)) {
			hql = hql + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			hqlC = hqlC + " and q.is_answered=:isAnswered and q.is_ignore=:ignore";
			if (isPublic) {
				hql = hql + " and q.is_public = 1";
				hqlC = hqlC + " and q.is_public = 1";
			}
			hql += " order by q.question_at desc";
		}

		Query query = s.createSQLQuery(hql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		Query queryc = s.createSQLQuery(hqlC);

		query.setInteger("userId", userId);
		queryc.setInteger("userId", userId);

		if ("all".equals(condition)) {

		}
		if ("answered".equals(condition)) {
			query.setInteger("isAnswered", 1);
			queryc.setInteger("isAnswered", 1);
		}
		if ("unanswered".equals(condition)) {
			query.setInteger("isAnswered", 0);
			query.setInteger("ignore", 0);
			queryc.setInteger("isAnswered", 0);
			queryc.setInteger("ignore", 0);
		}
		if ("ignore".equals(condition)) {
			query.setInteger("isAnswered", 0);
			query.setInteger("ignore", 1);
			queryc.setInteger("isAnswered", 0);
			queryc.setInteger("ignore", 1);
		}

		query.setMaxResults(pageSize);
		query.setFirstResult((page - 1) * pageSize);

		int count = Integer.parseInt((queryc.uniqueResult().toString()));
		Page pageIns = new Page(count, pageSize, page);
		pageIns.setList(query.list());
		return pageIns;

	}

	public Page findAnsweredByPage(int userId, int page, int pageSize) {
		return findByPage(userId, page, pageSize, "answered", false);
	}

	public Page findAnsweredByPagePublic(int userId, int page, int pageSize) {
		return findByPage(userId, page, pageSize, "answered", true);
	}

	public Page findUnAnsweredByPage(int userId, int page, int pageSize) {
		return findByPage(userId, page, pageSize, "unanswered", false);
	}

	public Page findIgnoreByPage(int userId, int page, int pageSize) {
		return findByPage(userId, page, pageSize, "ignore", false);
	}

	public Page findSendQuestionByPage_All(int userId, int page, int pageSize) {
		return findSendQuestionsByPage(userId, page, pageSize, "all", false);
	}

	public Page findSendQuestionByPage_AnswerdAll(int userId, int page, int pageSize) {
		return findSendQuestionsByPage(userId, page, pageSize, "answered", false);
	}

	public Page findSendQuestionByPage_AnswerdPublic(int userId, int page, int pageSize) {
		return findSendQuestionsByPage(userId, page, pageSize, "answered", true);
	}

	public Page findSendQuestionByPage_UnAsnwerd(int userId, int page, int pageSize) {
		return findSendQuestionsByPage(userId, page, pageSize, "unanswered", false);
	}

	public Page findSendQuestionByPage_Ignored(int userId, int page, int pageSize) {
		return findSendQuestionsByPage(userId, page, pageSize, "ignore", false);
	}

	public void addQuestionTag(int tagId, int questionId) {
		Session s = sessionFactory.getCurrentSession();
		String sql = "insert into question_tag(question_id,tag_id) values(:questionId,:tagId)";
		Query query = s.createSQLQuery(sql);
		query.setInteger("questionId", questionId);
		query.setInteger("tagId", tagId);
		query.executeUpdate();
	}

	public boolean isTagExist(int tagId, int questionId) {
		Session s = sessionFactory.getCurrentSession();
		String sql = "select count(*) from question_tag qt where qt.tag_id=:tagId and qt.question_id=:questionId";
		Query query = s.createSQLQuery(sql);
		query.setInteger("questionId", questionId);
		query.setInteger("tagId", tagId);

		int count = Integer.parseInt((query.uniqueResult().toString()));
		if (count > 0) {
			return true;
		}
		else {
			return false;
		}
	}

	@SuppressWarnings("unchecked")
	public List<HashMap> findByIds(String ids) {
		if (ids.length() > 0) {
			Session s = sessionFactory.getCurrentSession();
			//String sql = "select q.* from question q where q.id in ("+ids+")";
			String sql = "select "
					+ "q.id,q.user_id as user_id,q.question_user_id as user_by_id,q.question,"
					+ "q.answer,q.question_at,q.answer_at,q.agree_num,q.disagree_num,q.favor_num,q.comments_num,q.collect_num,"
					+ "q.user_score,q.is_answered,q.is_elite,q.is_ignore,q.is_public,q.is_anonymous,"
					+ "u.name as user_name,u.head_img as user_head,ub.name as user_by_name,ub.head_img as user_by_head "
					+ "from question q " + "inner join user u on u.id=q.user_id "
					+ "inner join user ub on ub.id=q.question_user_id " + "where q.id in (" + ids
					+ ")";
			//System.out.println(sql);
			//String hql = "From Question a inner join fetch a.userByUserId u where a.id in ("+ids+")";
			//Query q = s.createQuery(hql);
			Query q = s.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
			List list = q.list();
			return list;
			//			List<QuestionJson> questionlist = new ArrayList<QuestionJson>();
			//			for (int i=0; i<list.size(); i++) {
			//				Map<String, Object> map = (Map<String, Object>) list.get(i); 
			//				QuestionJson question = new QuestionJson();
			//				question.setId((Integer) map.get("id"));
			//				question.setQuestion((String)map.get("question"));
			//				question.setAnswer((String)map.get("answer"));
			//				question.setQuestionAt((Date)map.get("question_at"));
			//				question.setAnswerAt((Date)map.get("answer_at"));
			//				question.setAgreeNum((Integer)map.get("agree_num"));
			//				question.setFavorNum((Integer)map.get("favor_num"));
			//				question.setUserScore((Integer)map.get("user_score"));
			//				question.setIsAnswered(((Byte)map.get("is_answered")) & 0xFF);
			//				question.setIsElite(((Byte)map.get("is_elite")) & 0xFF);
			//				question.setIsIgnore(((Byte)map.get("is_ignore")) & 0xFF);
			//				question.setIsPublic(((Byte)map.get("is_public")) & 0xFF);
			//				question.setIsAnonymous(((Byte)map.get("is_anonymous")) & 0xFF);
			//				
			//				question.setUserId((Integer) map.get("user_id"));
			//				question.setUserName((String)map.get("user_name"));
			//				question.setUserHead((String)map.get("user_head"));
			//
			//				question.setUserById((Integer) map.get("user_by_id"));
			//				question.setUserByName((String)map.get("user_by_name"));
			//				question.setUserByHead((String)map.get("user_by_head"));
			//				User userby = new User("");
			//
			//				questionlist.add(question);
			//			}
			//			return questionlist;
		}
		return new ArrayList();
	}

	public void addCommentNum(int qid) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "update Question as q set q.commentsNum=q.commentsNum+1 where q.id=:id";
		Query q = s.createQuery(hql);
		q.setInteger("id", qid);
		q.executeUpdate();
	}

	public void collect(int id) {
		Session s = sessionFactory.getCurrentSession();
		String hql = "update Question as q set q.collectNum=q.collectNum+1 where q.id=:id";
		Query q = s.createQuery(hql);
		q.setInteger("id", id);
		q.executeUpdate();
	}

	public List<Tag> findTagsByQuestionId(int questionId) {
		// TODO Auto-generated method stub
		Session s = sessionFactory.getCurrentSession();
		String hql = "select t.* from tag t where t.id in (select qt.tag_id from question_tag as qt where qt.question_id=:questionId)";
		Query query = s.createSQLQuery(hql).addEntity(Tag.class);
		query.setInteger("questionId", questionId);
		List<Tag> tags = query.list();
		return tags;
	}

	public Map findQuestionByIdWithUser(int questionId) {
		// TODO Auto-generated method stub
		Session s = sessionFactory.getCurrentSession();
		String sql = "select q.*,u.name as user_name,u.head_img as user_head,ub.name as user_by_name,ub.head_img as user_by_head "
				+ "from question q "
				+ "inner join user u on u.id=q.user_id "
				+ "inner join user ub on ub.id=q.question_user_id " + "where q.id=:questionId";

		Query q = s.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		q.setInteger("questionId", questionId);
		List list = q.list();
		if (list.size() > 0) {
			return (Map) list.get(0);
		}
		return null;
	}

	public List findNewQuestionTopN(int topN) {
		// TODO Auto-generated method stub
		Session s = sessionFactory.getCurrentSession();
		String sql = "select q.*,u.id as user_id,u.name as user_name,u.head_img as user_head,ub.id as user_by_id,ub.name as user_by_name,ub.head_img as user_by_head"
				+ " from question q inner join user u on q.user_id=u.id inner join user ub on q.question_user_id=ub.id where q.is_public=1 and q.is_answered=1 order by q.answer_at desc";
		
		Query query = s.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		query.setMaxResults(topN);
		return query.list();
	}

	public List findHotQuestionTopN(int topN) {
		// TODO Auto-generated method stub
		Session s = sessionFactory.getCurrentSession();
		String sql = "select q.*,u.id as user_id,u.name as user_name,u.head_img as user_head,ub.id as user_by_id,ub.name as user_by_name,ub.head_img as user_by_head"
				+ " from question q inner join user u on q.user_id=u.id inner join user ub on q.question_user_id=ub.id where q.is_public=1 and q.is_answered=1 order by (q.agree_num+q.disagree_num+q.favor_num+q.comments_num+q.collect_num) desc";
		Query query = s.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		query.setMaxResults(topN);
		return query.list();
	}

}
